/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2GraphicsOpenGL.h 28 2012-07-28 17:03:06Z trzntaat $
 * $Revision: 28 $
 */

#ifndef T2GRAPHICSOPENGL_H_INCLUDED
#define T2GRAPHICSOPENGL_H_INCLUDED


#include "T2DynamicArray.h"


namespace turska
{
    //! Implementation of Turska Graphics which uses OpenGL 1.2 or OpenGL ES 1.1.
    /** stb_image is used for image loading.
     */
    class GraphicsOpenGL : public turska::Graphics
    {
    public:

        static const int INIT_BATCH_RESERVE_QUADS = 256;

        GraphicsOpenGL(I32 windowWidth, I32 windowHeight) :
            mDefaultFlags(IF_DEFAULT_FLAGS), mWindowWidth(windowWidth), mWindowHeight(windowHeight),
            mBatchPositions(INIT_BATCH_RESERVE_QUADS * 8),
            mBatchTexCoords(INIT_BATCH_RESERVE_QUADS * 8),
            mBatchColors(INIT_BATCH_RESERVE_QUADS * 16),
            mBatchIndices(INIT_BATCH_RESERVE_QUADS * 6),
            mCurrentBatchVertexCount(0), mCurrentBatchTriangleCount(0),
            mCurrentBatchTextureGLId(0), mCurrentBatchDrawMode(IDM_NORMAL)
        {
            for (int a = 0; a < 16; ++a) mInitialModelViewMatrix[a] = (a % 5 == 0) ? 1.0f : 0.0f;
        }
        virtual ~GraphicsOpenGL() {}

        // From turska::Graphics:

        virtual void beginRender();
        virtual void endRender();

        virtual void setDefaultFlags(UI32 flags) { mDefaultFlags = flags; }

        virtual Image * loadImage(const C8 *fileName,
                                  UI32 flags = G_USE_DEFAULT_FLAGS);

        virtual void flush();

        // GraphicsOpenGL additions:

        //! Sets the current OpenGL window size.
        void setWindowSize(I32 windowWidth, I32 windowHeight)
        {
            mWindowWidth = windowWidth;
            mWindowHeight = windowHeight;
        }

        void setInitialViewMatrix(const float *m) { for (int a = 0; a < 16; ++a) mInitialModelViewMatrix[a] = m[a]; }

        //! Loads and constructs an Image from a file in memory.
        /*!
         * \param buffer buffer containing image file to load from.
         * \param length length of buffer in bytes.
         * \param flags image flags to use when loading image.
         *              \sa turska::IMAGE_FLAG
         * \return image object if successful, or 0 if unsuccessful.
         */
        Image * loadImage(const UI8 *buffer, I32 length,
                          UI32 flags = G_USE_DEFAULT_FLAGS);

        //! Constructs an Image from given raw image data.
        /*! Currently only image data with 32 bpp pixels is accepted,
         *  with byte components in R, G, B, A order for each pixel.
         * \param buffer buffer containing raw image data.
         * \param width width of buffer image in pixels.
         * \param height height of buffer image in pixels.
         * \param flags image flags to use when constructing image.
         *              \sa turska::IMAGE_FLAG
         * \param sourceRect optional source rectangle to crop from the surface,
         *                   or 0 to use the whole surface.
         * \param components number of byte components per pixel, only 4 is
         *                   supported for now.
         * \return image object if successful, or 0 if unsuccessful.
         */
        virtual Image * createImage(const UI8 *buffer,
                                    I32 width, I32 height, UI32 flags,
                                    PixelRectangle *sourceRect = 0,
                                    I32 components = 4);

        //! Creates an OpenGL texture from given raw image data.
        /*! Currently only image data with 32 bpp pixels is accepted,
         *  with byte components in R, G, B, A order for each pixel.
         * \param oTexture resulting OpenGL texture name, when successful.
         * \param oUV resulting top-left and bottom-right U,V coordinates
         *            in texture (4 floats), when successful.
         * \param buffer buffer containing raw image data.
         * \param width width of buffer image in pixels.
         * \param height height of buffer image in pixels.
         * \param flags image flags to use when constructing image.
         *              \sa turska::IMAGE_FLAG
         * \param sourceRect optional source rectangle to crop from the surface,
         *                   or 0 to use the whole surface.
         * \param components number of byte components per pixel, only 4 is
         *                   supported for now.
         * \return true if successful, or false if unsuccessful.
         */
        virtual bool createTexture(UI32 &oTexture, F32 *oUV,
                                   const UI8 *buffer,
                                   I32 width, I32 height, UI32 flags,
                                   PixelRectangle *sourceRect = 0,
                                   I32 components = 4);

        void prepareBatch(UI32 textureGLId, turska::IMAGE_DRAW_MODE drawMode, bool forceFlush);
        void batchImageDraw(UI32 textureGLId, turska::IMAGE_DRAW_MODE drawMode, const F32 *positions, const F32 *texCoords, const UI8 *colors);

        DynamicArray<UI16> & getBatchIndices() { return mBatchIndices; }
        DynamicArray<F32> & getBatchPositions() { return mBatchPositions; }
        DynamicArray<F32> & getBatchTexCoords() { return mBatchTexCoords; }
        DynamicArray<UI8> & getBatchColors() { return mBatchColors; }
        void addToBatchSize(I32 vertexCount, I32 triangleCount) { mCurrentBatchVertexCount += vertexCount; mCurrentBatchTriangleCount += triangleCount; }

        // Returns cumulative batch count (draw calls) rendered after last call to beginRender().
        I32 getStatBatchCount() const { return mStatBatchCount; }
        // Returns cumulative triangle count rendered after last call to beginRender().
        I32 getStatTriangleCount() const { return mStatTriangleCount; }

    protected:

        UI32 mDefaultFlags;
        I32 mWindowWidth, mWindowHeight;
        float mInitialModelViewMatrix[16];

        DynamicArray<F32> mBatchPositions; // 2 floats per vertex
        DynamicArray<F32> mBatchTexCoords; // 2 floats per vertex
        DynamicArray<UI8> mBatchColors;      // 4 bytes (RGBA) per vertex
        DynamicArray<UI16> mBatchIndices;    // 3 indices per triangle (and 2 triangles per quad = 6 indices per quad)
        I32 mCurrentBatchVertexCount, mCurrentBatchTriangleCount;
        UI32 mCurrentBatchTextureGLId;
        IMAGE_DRAW_MODE mCurrentBatchDrawMode;

        I32 mStatBatchCount;
        I32 mStatTriangleCount;
    
    }; // GraphicsOpenGL
} // namespace turska


#endif // !T2GRAPHICSOPENGL_H_INCLUDED
